// To change this License template, choose Tools / Templates
// and edit Licenses / FanDefaultLicense.txt
//
// History:
//   07.09.2010 JSTAUDEMEYER Creation
//

using Midi

**
** Music
**
class Music
{
  new make(|This| t) { t(this) }

    static const Int[] scale := [0,2,4,5,7,9,11]
    Note n(Int pitch, Int oct:=0) { Note(pitch+oct*12) }
    Note c(Int oct:=0) { n(scale[0],oct) }
    Note d(Int oct:=0) { n(scale[1],oct) }
    Note e(Int oct:=0) { n(scale[2],oct) }
    Note f(Int oct:=0) { n(scale[3],oct) }
    Note g(Int oct:=0) { n(scale[4],oct) }
    Note a(Int oct:=0) { n(scale[5],oct) }
    Note b(Int oct:=0) { n(scale[6],oct) }
    Rest r() { Rest() }

    private SequenceBuilder sb := SequenceBuilder()
    private Bool closed := false

    Voice[] voices := [,]

    Voice newVoice(Int instrument:=0) {
      tb := sb.newTrack
      tb.programmChange(instrument)
      v := Voice(tb)
      voices.add(v)
      return v
    }

    Void close() {
      if (!closed) {
        sb.close
        closed = true
      }
    }

  Void play() {
    close
    sb.play
  }

  Void dump() {
    SequenceDumper.make.dump(sb.sequence)
  }

}

class Voice {

  private TrackBuilder tb

  Int level := 60

  new make (TrackBuilder trackBuilder) {
    tb = trackBuilder
  }

  Void sendNote(Note n) {
    pitch := n.pitch+level
    tb.noteOn(pitch,n.velocity)
    if (n.accord!=null) {
      n.accord.each { tb.noteOn(pitch+it,n.velocity) }
    }
    tb.advance((n.length * SequenceBuilder.WHOLE).toInt)
    tb.noteOff(pitch,n.velocity)
    if (n.accord!=null) {
      n.accord.each { tb.noteOff(pitch+it,n.velocity) }
    }
  }

  Void sendTune(Tune t) {
    t.notes.each { sendNote(it) }
  }

  Void send (MusicElement m) {
    if (m is Note) {
      sendNote((Note)m)
    } else {
      sendTune((Tune)m)
    }
  }
}

